package com.cmcc.pcap.packet.sctp.ngaps;

import com.cmcc.packet.entity.NGAP.NgapEntity;
import com.cmcc.pcap.packet.sctp.SctpConnection;
import com.cmcc.pcap.packet.sctp.SctpPacketDecorator;
import com.cmcc.pcap.packet.sctp.nas.NasDecoder;
import com.cmcc.pcap.packet.sctp.nas.core.messages.NasMessage;
import com.ericsson.mts.asn1.NGAPDecoder;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.pcap4j.packet.SctpPacket;
import org.pcap4j.packet.namednumber.SctpChunkType;
import org.pcap4j.util.ByteArrays;

import java.io.IOException;
import java.util.ArrayList;

public class NgapMessages {

    //存放ngap报文原始的sctp连接
    public SctpConnection sctpconnection;

    public static Logger logger = LogManager.getLogger(NgapMessages.class);

    //存放从原始sctp连接中找出来的包含ngap的报文
    public ArrayList<SctpPacketDecorator> al_filtered;

    public NgapMessages(SctpConnection sctpconnection) {
        this.sctpconnection = sctpconnection;
        al_filtered = new ArrayList<>();
    }

    public void decodeNgapPdu(SctpPacket.SctpChunk sctpChunk, NgapEntity ngapEntity, NGAPDecoder decoder) throws IOException {
        //判断chunk的类型是否是DATA，若是，再获取其中的USER DATA
        if (!sctpChunk.getType().name().equals(SctpChunkType.DATA.name())){
            return;
        }

        /**
         * 获取datachunk的数据部分，即为NGAP报文
         * CHUNK 的length = 16+UserDataLength，length字段不包含报文末尾补充的padding字段，padding字段最长为3个字节的0
         */
        // 解码ngap报文
        byte [] userData = ByteArrays.getSubArray(sctpChunk.getRawData(),16,sctpChunk.length()-16);
        String result = decoder.decodeNgapToJson(userData);
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode ngapJsonValue = objectMapper.readTree(result);
        // 解析nas
        parseNasPdu(ngapJsonValue);
        ngapEntity.setNgapValue(objectMapper.writeValueAsString(ngapJsonValue));
        fitler_ngap(ngapEntity, ngapJsonValue);
    }

    private void fitler_ngap(NgapEntity ngapEntity, JsonNode ngapJsonValue) {
        JsonNode successfullOutcome = ngapJsonValue.get("successfulOutcome");
        JsonNode initiatingMessage = ngapJsonValue.get("initiatingMessage");
        JsonNode unsuccessfulOutcome = ngapJsonValue.get("unsuccessfulOutcome");
        JsonNode common = null;
        if (successfullOutcome != null){
            ngapEntity.setNgapPduType("successfulOutcome");
            common = successfullOutcome;
        }
        if (initiatingMessage != null){
            ngapEntity.setNgapPduType("initiatingMessage");
            common = initiatingMessage;
        }
        if (unsuccessfulOutcome != null){
            ngapEntity.setNgapPduType("unsuccessfulOutcome");
            common = unsuccessfulOutcome;
        }
        ngapEntity.setCriticality(common.get("criticality").asText());
        ngapEntity.setProcedureCode(common.get("procedureCode").asInt());
        String messageType = common.get("value").fieldNames().next();
        ngapEntity.setNgapMessageType(messageType);
    }

    private static void parseNasPdu(JsonNode node) {
        if (node.isObject()) {
            ObjectNode objectNode = (ObjectNode) node;
            objectNode.fields().forEachRemaining(entry -> {
                if ("NAS-PDU".equals(entry.getKey())) {
                    String value = entry.getValue().asText();
                    NasMessage nas = NasDecoder.nasPdu(value);
                    ObjectMapper mapper = new ObjectMapper();
                    JsonNode t = mapper.valueToTree(nas);
                    objectNode.put(entry.getKey(), t);
                } else {
                    parseNasPdu(entry.getValue());
                }
            });
        } else if (node.isArray()) {
            node.forEach(NgapMessages::parseNasPdu);
        }
    }
}